package com.bbex.service.impl;

import com.bbex.constant.Constants;
import com.bbex.entity.*;
import com.bbex.entity.otc.OtcOfflineOrder;
import com.bbex.entity.otc.OtcOfflineOrderDetail;
import com.bbex.enums.ExTypeEnum;
import com.bbex.enums.OfflineTransferLogEnum;
import com.bbex.enums.UserCoinVolumeEventEnum;
import com.bbex.enums.VolumeTypeEnum;
import com.bbex.exception.PlatException;
import com.bbex.mapper.HongmengCoinHidVolumeDao;
import com.bbex.mapper.HongmengCoinVolumeDao;
import com.bbex.mapper.OfflineTransferLogDao;
import com.bbex.mapper.UserCoinVolumeDao;
import com.bbex.pojo.ResponsePage;
import com.bbex.pojo.UserCoinVolumeBillDTO;
import com.bbex.service.HongmengCoinHidVolumeService;
import com.bbex.service.UserCoinVolumeBillService;
import com.bbex.service.UserCoinVolumeExService;
import com.bbex.util.SnowFlake;
import com.bbex.vo.CoinoutListVO;
import com.bbex.vo.DepdrawLogVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Service
public class HongmengCoinHidVolumeServiceImpl implements HongmengCoinHidVolumeService {

    /**
     * logger
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(HongmengCoinHidVolumeServiceImpl.class);

    @Autowired
    private HongmengCoinHidVolumeDao hongmengCoinHidVolumeDao;
    @Autowired
    private  OfflineTransferLogDao offlineTransferLogDao;
    @Autowired
    private  UserCoinVolumeExService userCoinVolumeService;
    @Autowired
    private UserCoinVolumeBillService userCoinVolumeBillService;
    @Autowired
    private UserCoinVolumeDao userCoinVolumeDao;

    @Override
    public List<HongmengCoinHidVolume> findHidAll(String userId) {
        return hongmengCoinHidVolumeDao.findHidAll(userId);
    }

    @Override
    public void updateById(HongmengCoinHidVolume hongmengCoinHidVolume) {

    }

    @Override
    @Transactional
    public void inOut(String userId, String coinId, BigDecimal volume, String symbol, String from, String to, String loginSource) {
        if(from.equals(VolumeTypeEnum.PT_VOLUME.getCode())){
            if(to.equals(VolumeTypeEnum.HID_VOLUME.getCode())){
                LOGGER.info("普通 到 hid");
                inhid(userId, coinId, volume, symbol);
            }
        }else if(from.equals(VolumeTypeEnum.HID_VOLUME.getCode())){
            if(to.equals(VolumeTypeEnum.PT_VOLUME.getCode())){
                LOGGER.info("hid 到 普通");
                outhid(userId, coinId, volume, symbol);
            }
        }

    }

    /**
     * 划转记录
     * @return
     */
    @Override
    public ResponsePage<OfflineTransferLog> findCoinoutLogPage(CoinoutListVO coinoutListVO) {
        ResponsePage<OfflineTransferLog> responsePage = new ResponsePage<>();
        Page<Object> page = PageHelper.startPage(coinoutListVO.getCurrentPage(), coinoutListVO.getShowCount());
        List<OfflineTransferLog> data = null;
        data = offlineTransferLogDao.findCoinoutPage(coinoutListVO.getUserId());
        responsePage.setCount(page.getTotal());
        responsePage.setList(data);
        return responsePage;
    }

    /**
     * 普通账户 转 hid账户
     */
    @Override
    @Transactional
    public void inhid(String userId, String coinId, BigDecimal volume, String symbol) {
        if (volume.compareTo(BigDecimal.ZERO) <= 0) {
            throw new PlatException(Constants.OPERRATION_ERROR, "操作失败,转入资金非法");
        }

        // 取常规划转之前账户资产，记录到transfer表source_volume字段，用于达子对账
        BigDecimal bbVolume = BigDecimal.ZERO; //
        //UserCoinVolume userCoinVolume =  userCoinVolumeService.findByUserIdAndCoinSymbol(userId, symbol);
        UserCoinVolume userCoinVolume =  userCoinVolumeDao.findByUserIdAndCoinSymbol(userId, symbol);
        if (Objects.nonNull(userCoinVolume)) {
            bbVolume = userCoinVolume.getVolume();
        }

        LOGGER.info("普通-hid 普通 update userId: " + userId + " bbVolume:" + volume);
        userCoinVolumeService.updateOutcomeException(null,volume,userId,symbol);

        //判断hid 是否有值
        HongmengCoinHidVolume hongmengCoinHidVolume = hongmengCoinHidVolumeDao.findByUserIdAndCoinId(userId, coinId);
//        if (null != userCoinVolume) {
//            if (userCoinVolume.getVolume().compareTo(volume) >= 0) {
                if (hongmengCoinHidVolume != null) {

                    LOGGER.info("普通-hid hid update userId: " + userId + " addVolume:" + volume);
                    long count = hongmengCoinHidVolumeDao.updateAddVolume(userId, coinId, volume);
                    if (count == 0) {
                        LOGGER.info("更新hid资产失败，普通-hid hid update userId: "+ userId + " addVolume:" + volume);
                        throw new PlatException(Constants.UPDATE_ERROR, "更新失败");
                    }
                } else {
                    hongmengCoinHidVolume = new HongmengCoinHidVolume();
                    String id = SnowFlake.createSnowFlake().nextIdString();
                    hongmengCoinHidVolume.setId(id);
                    hongmengCoinHidVolume.setVolume(volume);
                    //hongmengCoinHidVolume.setAdvertVolume(BigDecimal.ZERO);
                    hongmengCoinHidVolume.setLockVolume(BigDecimal.ZERO);
                    //hongmengCoinHidVolume.setBailVolume(BigDecimal.ZERO);
                    hongmengCoinHidVolume.setCreateDate(LocalDateTime.now());
                    hongmengCoinHidVolume.setUpdateDate(LocalDateTime.now());
                    hongmengCoinHidVolume.setUserId(userId);
                    hongmengCoinHidVolume.setCoinId(coinId);
                    hongmengCoinHidVolume.setCoinSymbol(symbol);
                    hongmengCoinHidVolume.setVersion(0L);
                    hongmengCoinHidVolumeDao.insert(hongmengCoinHidVolume);
                }
                //写入 转入日志日志
                Integer type = Integer.parseInt(OfflineTransferLogEnum.COIN_TO_HID.getCode());
                this.saveLog(userId, coinId, symbol, volume, type, bbVolume);
//            } else {
//                throw new PlatException(Constants.OPERRATION_ERROR, "操作失败,可用资金不足");
//            }
//        } else {
//            throw new PlatException(Constants.OPERRATION_ERROR, "操作失败,可用资金不足");
//        }
    }

    /**
     * @param userId
     * @param coinId
     * @param coinSymbol
     * @param volume
     * @param type
     * @param sourceVolume  取划转之前from账户资产，记录到transfer表source_volume字段，用于达子对账
     * @return
     */
    private OfflineTransferLog saveLog(String userId, String coinId, String coinSymbol, BigDecimal volume, Integer type, BigDecimal sourceVolume) {
        OfflineTransferLog offlineTransferLog = new OfflineTransferLog();
        String id = SnowFlake.createSnowFlake().nextIdString();
        offlineTransferLog.setId(id);
        offlineTransferLog.setCreateDate(LocalDateTime.now());
        offlineTransferLog.setUpdateDate(LocalDateTime.now());
        offlineTransferLog.setUserId(userId);
        offlineTransferLog.setCoinSymbol(coinSymbol);
        offlineTransferLog.setVolume(volume);
        offlineTransferLog.setType(type);
        offlineTransferLog.setCoinId(coinId);
        offlineTransferLog.setSourceVolume(sourceVolume);
        offlineTransferLogDao.insert(offlineTransferLog);
        return offlineTransferLog;
    }

    /**
     * hid 转 普通
     *
     * @param userId
     * @param coinId
     * @param volume
     * @param symbol
     */
    @Override
    @Transactional
    public void outhid(String userId, String coinId, BigDecimal volume, String symbol) {
        if (volume.compareTo(BigDecimal.ZERO) <= 0) {
            throw new PlatException(Constants.OPERRATION_ERROR, "操作失败,转出资金非法");
        }
        //判断币币账户该资产
//        UserCoinVolume userCoinVolume = userCoinVolumeDao.findByUserIdAndCoinId(userId, coinId);
        HongmengCoinHidVolume hongmengCoinHidVolume = hongmengCoinHidVolumeDao.findByUserIdAndCoinId(userId, coinId);
        if (hongmengCoinHidVolume != null) {
            if (hongmengCoinHidVolume.getVolume().compareTo(volume) >= 0) {
                //off sub
                BigDecimal subVolume = hongmengCoinHidVolume.getVolume().subtract(volume);
                if (subVolume.compareTo(BigDecimal.ZERO) < 0) {
                    throw new PlatException(Constants.OPERRATION_ERROR, "操作非法");
                }
                Timestamp timestamp = Timestamp.valueOf(hongmengCoinHidVolume.getUpdateDate());
                LOGGER.info("hid-普通 hid update userId: " + userId + " subVolume:" + subVolume);
                long count = hongmengCoinHidVolumeDao.updateHidVolume(userId, coinId, subVolume, timestamp, hongmengCoinHidVolume.getVersion());
                if (count == 0) {
                    throw new PlatException(Constants.UPDATE_ERROR, "更新失败");
                }
                //bb add
                //判断币币账户是否有资产
              /*  if (userCoinVolume != null) {
                    BigDecimal addVolume = userCoinVolume.getVolume().add(volume);
                    timestamp = Timestamp.valueOf(userCoinVolume.getUpdateDate());
                    LOGGER.info("c2c-bb bb update userId: " + userId + " addVolume:" + addVolume);
                    count = userCoinVolumeDao.updateVolume(userId, coinId, addVolume, timestamp);
                    if (count == 0) {
                        throw new PlatException(Constants.UPDATE_ERROR, "更新失败");
                    }
                    redisCacheManager.cleanUserCoinVolume(userId, symbol);
                } else {
                    userCoinVolume = new UserCoinVolume();
                    String id = SnowFlake.createSnowFlake().nextIdString();
                    userCoinVolume.setId(id);
                    userCoinVolume.setVolume(volume);
                    userCoinVolume.setLockVolume(BigDecimal.ZERO);
                    userCoinVolume.setOutLockVolume(BigDecimal.ZERO);
                    userCoinVolume.setCreateDate(LocalDateTime.now());
                    userCoinVolume.setUpdateDate(LocalDateTime.now());
                    userCoinVolume.setUserId(userId);
                    userCoinVolume.setCoinId(coinId);
                    userCoinVolume.setCoinSymbol(symbol);
                    userCoinVolume.setFlag((short) 0);

                    userCoinVolumeDao.insert(userCoinVolume);
                    redisCacheManager.cleanUserCoinVolume(userId, symbol);
                }*/
//                userCoinVolumeService.updateIncomeException(null,volume,userId,symbol);
                //写入 转入日志日志
                Integer type = Integer.parseInt(OfflineTransferLogEnum.HID_TO_COIN.getCode());
                OfflineTransferLog offlineTransferLog = this.saveLog(userId, coinId, symbol, volume, type, hongmengCoinHidVolume.getVolume());
                //生成币币资产变更记录
                this.saveCoinVolumeBillDTO(symbol, userId, volume, "hid转普通", offlineTransferLog.getId());
            } else {
                throw new PlatException(Constants.OPERRATION_ERROR, "操作失败,可用资金不足");
            }
        } else {
            throw new PlatException(Constants.OPERRATION_ERROR, "操作失败,可用资金不足");
        }
    }

    private void checkOtcOrderParam(OtcOfflineOrder otcOfflineOrder) {
        greaterZero(otcOfflineOrder.getVolume(), null);
        greaterZero(otcOfflineOrder.getSuccessVolume(), null);
        greaterZero(otcOfflineOrder.getLockVolume(), null);
    }

    private void checkOtcDetailParam(OtcOfflineOrderDetail otcOfflineOrderDetail) {
        greaterZero(otcOfflineOrderDetail.getVolume(), null);
        if (!String.valueOf(ExTypeEnum.SELL.getCode()).equals(otcOfflineOrderDetail.getExType())) {
            throw new PlatException(Constants.PARAM_ERROR, "订单的卖币方参数错误");
        }
    }

    /*@Transactional
    public void saveCoinVolumeInfo(OfflineCoinVolume offlineCoinVolume, String batchNo) {
        checkCoinVolumeInfo(offlineCoinVolume);
        //offlineCoinVolumeLogService.saveLog(offlineCoinVolume.getUserId(), offlineCoinVolume.getCoinId(), batchNo);// C2C资产流水
        long count = offlineCoinVolumeDao.updateCoinVolumeInfo(offlineCoinVolume);
        if (count != 1) {
            throw new PlatException(Constants.UPDATE_ERROR, "更新失败");
        }
        offlineCoinVolumeLogService.saveLog(offlineCoinVolume.getUserId(), offlineCoinVolume.getCoinId(), batchNo);// C2C资产流水
    }*/

    private void checkCoinVolumeInfo(OfflineCoinVolume offlineCoinVolume) {
        greaterZero(offlineCoinVolume.getVolume(), "用户资产不足");
        greaterZero(offlineCoinVolume.getAdvertVolume(), "用户广告锁定错误");
        greaterZero(offlineCoinVolume.getLockVolume(), "用户交易锁定错误");
        greaterZero(offlineCoinVolume.getOtcAdvertVolume(), "用户OTC广告锁定错误");
        greaterZero(offlineCoinVolume.getOtcLockVolume(), "用户OTC交易锁定错误");
    }

    private void greaterZero(BigDecimal target, String errorMsg) {
        if (Objects.isNull(target) || target.compareTo(BigDecimal.ZERO) == -1) {
            LOGGER.error("参数错误{}", target);
            throw new PlatException(Constants.PARAM_ERROR, Optional.ofNullable(errorMsg).orElse("参数错误"));
        }
    }

    private void saveCoinVolumeBillDTO(String coinSymbol, String userId, BigDecimal volume, String mark, String refKey){
        UserCoinVolumeBillDTO billDTO = new UserCoinVolumeBillDTO();
        //String id = SnowFlake.createSnowFlake().nextIdString();
        //billDTO.setId(id);
        billDTO.setCoinSymbol(coinSymbol);
        billDTO.setForceLock(true);
        billDTO.setMark(mark);
        billDTO.setOpLockVolume(new BigDecimal(0));
        billDTO.setOpVolume(volume);
        billDTO.setUserId(userId);
        //billDTO.setOpSign(MiningEnum.ADD_VOLUME.getCode());
        billDTO.setOpSign(new UserCoinVolumeEventEnum[]{UserCoinVolumeEventEnum.ADD_VOLUME});
        billDTO.setPriority(5);
        billDTO.setRefKey(refKey);
        billDTO.setSource("TRANSFER");
        userCoinVolumeBillService.insert(billDTO);
    }
}
